home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c
- Path: news.sprintlink.net!eskimo!scs
- From: scs@eskimo.com (Steve Summit)
- Subject: Re: more problems with qsort
- X-Nntp-Posting-Host: eskimo.com
- Message-ID: <DnpBFK.7nv@eskimo.com>
- Sender: news@eskimo.com (News User Id)
- Organization: schmorganization
- References: <4h0j9e$ng5@clarknet.clark.net> <4h81m0$avr@solutions.solon.com> <4hba5n$2ga@clarknet.clark.net>
- Date: Sun, 3 Mar 1996 17:04:30 GMT
-
- In article <4hba5n$2ga@clarknet.clark.net>, yom@clark.net writes:
- > In article <4h81m0$avr@solutions.solon.com>, seebs@solutions.solon.com
- > says...
- >> In article <4h0j9e$ng5@clarknet.clark.net>, yom <yom@clark.net> wrote:
- >> >And your compare function must be defined like this:
- >> >int compare(char **a,char **b) {return strcmp(*a,*b);}
- >>
- >> No, it really mustn't. It must be defined like this:
- >> int compare(const void *a, const void *b) {
- >> return strcmp(*(char **) a, *(char **) b);
- >> }
- >
- > Well I disagree on this one. Results of 1) defining the compare
- > function that takes two char** arguments and casting the function call
- > to qsort and 2) defining the compare function that takes two void*
- > arguments and casting the arguments to char ** in strcmp call are
- > identical.
-
- The *results* *on your system* may have been identical, but the
- two code fragments most certainly are not.
-
- If I may take the liberty of quoting from "C Programming FAQs:
- Frequently Asked Questions", Addison-Wesley, 1996:
-
- To understand why the curious pointer conversions in a qsort
- comparison function are necessary (and why a cast of the
- function pointer when calling qsort() can't help), it's useful
- to think about how qsort() works. qsort() doesn't know
- anything about the type or representation of the data being
- sorted: it just shuffles around little chunks of memory.
- (All it knows about the chunks is their size, which you
- specify in qsort()'s third argument.) To determine whether
- two chunks need swapping, qsort() calls your comparison
- function. (To swap them, it uses the equivalent of memcpy().)
-
- Since qsort() deals in a generic way with chunks of memory of
- unknown type, it uses generic pointers (void *) to refer to
- them. When qsort() calls your comparison function, it passes
- as arguments two generic pointers to the chunks to be
- compared. Since it passes generic pointers, your comparison
- function must *accept* generic pointers, and convert the
- pointers back to their appropriate type before manipulating
- them (i.e. before performing the comparison). A void pointer
- is not the same type as a structure pointer, and on some
- machines it may have a different size or representation
- (which is why these casts are required for correctness).
-
- If you were sorting an array of structures, and had a
- comparison function accepting structure pointers:
-
- int mywrongstructcmp(struct mystruct *, struct mystruct *);
-
- and if you called qsort() as
-
- qsort(dates, ndates, sizeof(struct mystruct),
- (int (*)(const void *, const void *))mywrongstructcmp);
- /* WRONG */
-
- the cast (int (*)(const void *, const void *)) would do
- nothing except perhaps silence the message from the compiler
- telling you that this comparison function may *not* work with
- qsort(). The implications of any cast you use when calling
- qsort will have been forgotten by the time qsort() gets around
- to calling your comparison function: it will call them with
- const void * arguments, so that is what your function must
- accept. No prototype mechanism exists which could operate
- down inside qsort() to convert the void pointers to struct
- mystruct pointers just before calling mywrongstructcmp().
-
- In general, it is a bad idea to insert casts just to "shut the
- compiler up." Compiler warnings are usually trying to tell
- you something, and unless you really know what you're doing,
- you ignore or muzzle them at your peril. See also question 4.9.
-
- Steve Summit
- scs@eskimo.com
-